#pragma once

namespace qb{
	namespace ht{
		class QuotaMap{
		public:
			class Listener{
			public:
				virtual void OnWrite(int rid, const void* prev, const void* cur, int size, bool insert){}
			};
			struct  Entry{
				Entry*		listprev;			// 新旧关系双链表的后一个
				Entry*		listnext;			// 新旧关系双链表的前一个
				Entry*		hashprev;			// 哈西插槽的双链表的后一个
				Entry*		hashnext;			// 哈西插槽的双链表的前一个
				int			rid;				// record-id，与记录内容一一对应的id，也是文件中的记录号
				int			changed;			// 当前记录已经被改写了多少次
				char		record[4];			// 其后面是数组，加上此4字节，总共是m_item_size字节，末尾可能还有0-3个的padding
			};
			typedef Entry* SLOT;
			SLOT*			m_slots;			// 哈希插槽，总共有m_slot_length个
			int				m_slot_length;		// 哈西插槽的长度，通常为质数
			int				m_count;			// 当前已经放入的记录个数
			int				m_capcity;			// 该数据结构设计好的容量，超过就需要将原先旧的记录替换出去
			char*			m_entry_array;		// 所有分配好的Entry*内存块
			Entry*			m_head;				// 永远指向最新的记录，头部，当更新记录的时候就移到头部
			Entry*			m_tail;				// 永远指向最旧的记录，尾部
			int				m_item_size;		// 记录的实际大小
			int				m_entry_size;		// Entry的实际大小
			Listener*		m_listener;			// 
		public:
			QuotaMap();
			~QuotaMap();

			void SetListener(Listener* listener){ m_listener = listener; }

			/*
				构建限额缓存表，使用前必须先Build
				*/
			void Build(int slot, int capcity, int itemsize);

			/*
				扩展该限额缓存表所能存储的最大记录个数
				*/
			void Expand(int capcity);


			/*
				将记录号为rid的记录record插入到此限额缓存表中
				swap_rid和swap_record用于接收可能被限额缓存表交换出来的记录
				内部假设record和swap_record都是固定大小的内存块，大小为m_item_size
				*/
			void Set(int rid, const void* record, int* swap_rid, char* swap_record, bool insert);

			/*
				从此限额缓存表中读取记录号为rid的记录到record内存中
				adjust 表示将此记录移到新旧双链表的头部使得其维持的时间更长
				*/
			bool Get(int rid, char* record, bool adjust = false);

			// 调试支持,用于获取一些信息
			int GetMemoryUsed()const;
			int GetCapcity()const{ return m_capcity; }
			int GetSlotLength()const{ return m_slot_length; }
			int GetCount()const{ return m_count; }
			int GetSlotValidCount();
			int GetSlotMaxLength(float* avgLength);
		protected:
			int GetSlot(int rid);
			void Swap(QuotaMap& qm);
			void AdjustId(Entry* et, int rid);
			Entry* PickTail(int* swap_rid, char* swap_record);
			void AdjustToHead(Entry* et);

			void CheckList();
			void CheckListHead();
			void CheckHashArray();
			void CheckSlot(Entry* entry);
			bool CheckSlot(int slot, Entry* entry);
		};
	}//namespace ht
}//namespace qb
